package com.example.java.concurrent.thread;

import java.util.concurrent.*;

// 线程示例，不论线程的创建形式怎么变，归根结底都是通过 new Thread(Runnable) 类来创建的.
// 例如：
// 1. 继承 Thread 类，重写 run() 方法
// 2. 实现 Runnable 接口，重写 run() 方法
// 3. 通过 Callable 和 Future 创建线程间接任务
// 4. 通过 Executor 创建线程池
public class ThreadMain {
    public static void main(String[] args) {
        // 创建新线程
        Thread thread = new Thread(() -> {
            // 线程执行的代码
            System.out.println("Hello from thread!");
        });
        thread.start(); // 启动线程


        // 创建线程任务，该任务没有返回值也没有抛异常
        Runnable runnable = () -> {
            // 线程执行的代码
            System.out.println("Hello from runnable!");
        };
        // 创建线程
        Thread thread2 = new Thread(runnable);
        thread2.start(); // 启动线程


        // 创建线程间接任务需要用 FutureTask 包装 Callable，该任务有返回值也可以抛异常
        Callable<String> callable = () -> {
            // 线程执行的代码
            return "Hello from callable!";
        };
        // FutureTask 类是 RunnableFuture<V> 接口的实现类，可以作为线程任务使用
        // 类只能单继承，但接口可以多继承，例如 RunnableFuture<V> 接口继承了 Runnable 和 Future<V> 两个接口
        // 在 FutureTask 类内部，实现的 Runnable 的run() 方法中，调用 callable 的 call() 方法，并将结果设置到 FutureTask 类的 result 字段中
        FutureTask<String> futureTask = new FutureTask<>(callable);// 创建 FutureTask 对象
        new Thread(futureTask).start(); // 启动线程
        try {
            System.out.println(futureTask.get()); // 获取线程执行结果
        } catch (Exception e) {
            e.printStackTrace();
        }


        // 创建一个具有给定初始参数的新 ThreadPoolExecutor
        int corePoolSize = 2;   // 核心线程数，保留在池中的线程数，即使它们处于空闲状态也不会被回收
        int maximumPoolSize = 5;    // 允许在池中的最大线程数
        long keepAliveTime = 10;    // 当线程数大于核心数时，这是多余的空闲线程在终止之前等待新任务的最长时间
        TimeUnit unit = TimeUnit.SECONDS;    // 线程空闲时间单位
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10);    // 在执行任务之前用于保存任务的队列。此队列仅保存由execute方法提交的Runnable任务
        // 线程工厂，用于创建新线程。根据需要在当前线程上创建新线程的对象
        ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 线程工厂，用于创建新线程。执行器创建新线程时要使用的工厂
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();    // 拒绝策略
        try {
            // 创建一个具有给定初始参数的新 ThreadPoolExecutor
            // ThreadPoolExecutor 类是一个线程池的实现，它允许你根据需要创建一个或多个线程池。它实现了 ExecutorService 接口
            // ExecutorService 接口继承了 Executor 接口，ExecutorService 接口提供了管理线程池的方法，例如 submit() 方法提交任务，shutdown() 方法关闭线程池。
            ExecutorService executorService = new ThreadPoolExecutor(
                    corePoolSize,
                    maximumPoolSize,
                    keepAliveTime,
                    unit,
                    workQueue,
                    threadFactory,
                    handler
            );
            executorService.execute(() -> {
                // 线程执行的代码
                System.out.println("Hello from executor!");
            });
            executorService.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭线程池
//            executorService.shutdown();
        }



        // Executors 工厂方法类可以用来创建一些简单的线程池，如果线程池配置比较复杂，可以使用 ThreadPoolExecutor 类来创建线程池
        // 使用 Executors 工厂方法创建线程池，上面的 ThreadPoolExecutor 是 ExecutorService 接口的实现类，因此也可以直接使用 Executors 工厂方法创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        executorService.execute(() -> {
            // 线程执行的代码
            System.out.println("Hello from executorService!");
        });
        // 关闭线程池
        executorService.shutdown();




        /*
        * 创建一个 Executor，为每个任务启动一个新的虚拟线程。Executor 创建的线程数是无限的。
        * 此方法等效于使用创建虚拟线程的线程工厂调用 newThreadPerTaskExecutor(ThreadFactory)
        * 返回值: 一个新的 executor，为每个任务创建一个新的虚拟 Thread
        */
        ExecutorService executorService1 = Executors.newVirtualThreadPerTaskExecutor();// 创建一个虚拟线程池，每个任务都是一个线程
        executorService1.execute(() -> {
            // 线程执行的代码
            System.out.println("Hello from virtual thread!");
        });
    }
}